package ta.example;

import ta.example.interfaces.FileHandler;
import ta.example.interfaces.StockSorter;
import ta.example.vo.StockInfo;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Formatter;
import java.util.Scanner;

public class Main {

    private static FileHandler fileHandler;

    private static StockSorter stockSorter;

    static{
        //TODO:Initialize fileHandler and stockSorter with your implement class
        fileHandler = new FileHandler()
        {
            @Override
            public StockInfo[] getStockInfoFromFile(String filePath)
            {
                ArrayList<StockInfo> stockInfos = new ArrayList<>();
                Scanner input = null;
                try
                {
                    input = new Scanner(new File(filePath));
                }
                catch (FileNotFoundException e)
                {
                    e.printStackTrace();
                }
                assert input != null;
                input.nextLine();
                while(input.hasNext())
                {
                    StockInfo info = new StockInfo();
                    String line = input.nextLine();
                    String[] contents = line.split("\t");

                    info.setId(Integer.parseInt(contents[0]));
                    info.setTitle(contents[1]);
                    info.setAuthor(contents[2]);
                    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                    Date date = new Date();
                    try
                    {
                        date = dateFormat.parse(contents[3]);
                    }
                    catch (ParseException e)
                    {
                        e.printStackTrace();
                    }
                    Date lastUpdate = new Date();
                    DateFormat dateFormat2 = new SimpleDateFormat("MM-dd HH:mm");
                    try
                    {
                        lastUpdate = dateFormat2.parse(contents[4]);
                    }
                    catch (ParseException e)
                    {
                        e.printStackTrace();
                    }
                    lastUpdate.setYear(date.getYear());
                    info.setDate(date);
                    info.setLastUpdate(lastUpdate);
                    info.setContent(contents[5]);
                    info.setAnswerAuthor(contents[6]);
                    //			System.out.println(line);
                    //			for (String str : contents)
                    //			{
                    //				System.out.println(str);
                    //			}
                    //
                    //			System.out.println(contents[6]);
                    info.setAnswer(contents[7]);
                    stockInfos.add(info);
                }
                input.close();
                StockInfo[] array = new StockInfo[stockInfos.size()];
                stockInfos.toArray(array);
                return array;
            }

            @Override
            public int setStockInfo2File(String filePath, StockInfo[] stocks)
            {
                int counter = 0;
                FileWriter writer = null;
                try
                {
                    writer = new FileWriter(filePath);
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                };
                try
                {
                    writer.write("ID\tTITLE\tAUTHOR\tDATE\tLASTUPDATE\tCONTENT\tANSWERAUTHOR\tANSWER\n");
                    for (StockInfo si : stocks)
                    {
                        counter++;
                        String str = si.getId() + "\t" + si.getTitle() + "\t" + si.getAuthor() + "\t";
                        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                        str += dateFormat.format(si.getDate()) + "\t";
                        DateFormat dateFormat2 = new SimpleDateFormat("MM-dd HH:mm");
                        str += dateFormat2.format(si.getLastUpdate()) + "\t";
                        str += si.getContent() + "\t" + si.getAnswerAuthor() + "\t" + si.getAnswer() + "\n";
                        writer.write(str);
                    }
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
                try
                {
                    writer.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
                return counter;
            }
        };
        class StockQuickSorter implements StockSorter
        {
            @Override
            public StockInfo[] sort(StockInfo[] info)
            {
                return sort(info, true);
            }

            @Override
            public StockInfo[] sort(StockInfo[] info, boolean order)
            {
                StockInfo[] infos = info.clone();
                quickSort(infos, 0, infos.length, order);
                return infos;
            }

            private void exchange(StockInfo[] a, int i, int j)
            {
                StockInfo m = a[i];
                a[i] = a[j];
                a[j] = m;
            }

            private int partition(StockInfo[] a, int i, int j)
            {
                StockInfo key = a[j-1];
                int lt = i;
                for (int l = i; l < j-1; l++)
                {
                    if (key.getAnswer().length() > a[l].getAnswer().length())
                    {
                        exchange(a, lt, l);
                        lt++;
                    }
                }
                exchange(a, lt, j -1);
                return lt;
            }

            private int reversePartition(StockInfo[] a, int i, int j)
            {
                StockInfo key = a[j-1];
                int lt = i;
                for (int l = i; l < j-1; l++)
                {
                    if (key.getAnswer().length() < a[l].getAnswer().length())
                    {
                        exchange(a, lt, l);
                        lt++;
                    }
                }
                exchange(a, lt, j -1);
                return lt;
            }

            public StockInfo[] quickSort(StockInfo[] a, boolean order)
            {
                StockInfo[] m = a.clone();
                quickSort(m, 0, a.length, order);
                return m;
            }

            private void quickSort(StockInfo[] a, int i, int j, boolean order)
            {
                if(i < j)
                {
                    int k = 0;
                    if (order)
                    {
                        k = partition(a, i, j);
                    }
                    else
                    {
                        k = reversePartition(a, i, j);
                    }
                    quickSort(a, i, k, order);
                    quickSort(a, k+1, j, order);
                }
            }
        }

        class BubbleSorter implements StockSorter
        {

            @Override
            public StockInfo[] sort(StockInfo[] info)
            {
                return sort(info, true);
            }

            @Override
            public StockInfo[] sort(StockInfo[] info, boolean order)
            {
                StockInfo[] infos = info.clone();
                for (int i = 0; i < infos.length - 1; i++)
                {
                    for (int j = 0; j < infos.length - 1 - i; j++)
                    {
                        if (infos[j].getAnswer().length() > infos[j+1].getAnswer().length())
                        {
                            exchange(infos, j, j+1);
                        }
                    }
                }
                return infos;
            }

            private void exchange(StockInfo[] a, int i, int j)
            {
                StockInfo temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }

        }

         class MergeSorter implements StockSorter
        {
            @Override
            public StockInfo[] sort(StockInfo[] info)
            {
                StockInfo[] i = info.clone();
                sort(i, 0, info.length - 1, true);
                return i;
            }

            public void sort(StockInfo[] info, int begin, int end, boolean order)
            {
                if(begin < end)
                {
                    int mid = begin + (end - begin) / 2;
                    sort(info, begin, mid, order);
                    sort(info, mid + 1, end, order);
                    stockMerge(info, begin, mid, end, order);
                }
            }

            private void stockMerge(StockInfo[] info, int begin, int mid, int end, boolean order)
            {

                StockInfo[] left = new StockInfo[mid - begin + 1];
                StockInfo[] right = new StockInfo[end - mid];
                for (int i = begin; i <= mid; i++)
                {
                    left[i - begin] = info[i];
                }
                for (int i = mid + 1; i <= end; i++)
                {
                    right[i - mid - 1] = info[i];
                }
                int i = 0;
                int j = 0;
                int pointer = begin;
                while (i != left.length || j != right.length)
                {
                    if (i == left.length)
                    {
                        info[pointer++] = right[j++];
                    } else if (j == right.length)
                    {
                        info[pointer++] = left[i++];
                    } else
                    if (order)
                    {
                        if (left[i].getAnswer().length() > right[j].getAnswer().length())
                        {
                            info[pointer++] = right[j++];
                        } else
                        {
                            info[pointer++] = left[i++];
                        }
                    }
                    else
                    {
                        if (left[i].getAnswer().length() < right[j].getAnswer().length())
                        {
                            info[pointer++] = right[j++];
                        } else
                        {
                            info[pointer++] = left[i++];
                        }
                    }
                }
            }
            @Override
            public StockInfo[] sort(StockInfo[] info, boolean order)
            {
                StockInfo[] i = info.clone();
                sort(i, 0, info.length - 1, order);
                return i;
            }
        }

         class Stock3WayQuickSorter implements StockSorter
        {
            @Override
            public StockInfo[] sort(StockInfo[] info)
            {
                return sort(info, true);
            }

            @Override
            public StockInfo[] sort(StockInfo[] info, boolean order)
            {
                StockInfo[] infos = info.clone();
                threeWayQuickSort(infos, order);
                return infos;
            }


            private void exchange(StockInfo[] a, int i, int j)
            {
                StockInfo m = a[i];
                a[i] = a[j];
                a[j] = m;
            }

            private int[] threeWayPartition(StockInfo[] a, int lo, int hi, boolean order)
            {
                int lt = lo;
                int i = lo + 1;
                StockInfo x = a[lo];
                int gt = hi;
                while(gt >= i)
                {
                    if (order?(a[i].getAnswer().length() < x.getAnswer().length() ): (a[i].getAnswer().length() > x
                            .getAnswer().length()))
                    {
                        exchange(a, i, lt);
                        i++;
                        lt++;
                    } else if (order?(a[i].getAnswer().length() > x.getAnswer().length()):(a[i].getAnswer().length() < x
                            .getAnswer().length()))
                    {
                        exchange(a, i, gt--);
                    } else
                    {
                        i++;
                    }
                }
                return new int[]{lt - 1, gt + 1};
            }

            private void threeWayQuickSort(StockInfo[] a, boolean order)
            {
                threeWayQuickSort(a, 0, a.length - 1, order);
            }

            private void threeWayQuickSort(StockInfo[] a, int p, int q, boolean order)
            {
                if(q >= p)
                {
                    int[] m = threeWayPartition(a, p, q, order);
                    threeWayQuickSort(a, p, m[0], order);
                    threeWayQuickSort(a, m[1], q, order);
                }
            }
        }

        class StockHeapSorter implements StockSorter
        {
            @Override
            public StockInfo[] sort(StockInfo[] info)
            {
                return sort(info, true);
            }

            @Override
            public StockInfo[] sort(StockInfo[] info, boolean order)
            {
                StockInfo[] infos = new StockInfo[info.length];
                MinPriorityQueue minPriorityQueue = new MinPriorityQueue(info.length);
                for (int i = 0; i < info.length; i++)
                {
                    minPriorityQueue.insert(info[i]);
                }
                if (order)
                {
                    for (int i = 0; i < info.length; i++)
                    {
                        infos[i] = minPriorityQueue.extractMin();
                    }
                }
                else
                {
                    for (int i = info.length-1; i >= 0; i--)
                    {
                        infos[i] = minPriorityQueue.extractMin();
                    }
                }
                return infos;
            }

            class MinPriorityQueue
            {

                private int heapSize;
                private StockInfo[] keys;

                private int right(int i)
                {
                    return i * 2 + 1;
                }

                private int left(int i)
                {
                    return i * 2;
                }

                private int parent(int i)
                {
                    return i / 2;
                }

                private void exchange(int i, int j)
                {
                    StockInfo m = keys[i];
                    keys[i] = keys[j];
                    keys[j] = m;
                }
                public void insert(StockInfo key)
                {
                    this.keys[heapSize + 1] = key;
                    this.heapSize += 1;
                    swim(heapSize);
                }

                MinPriorityQueue(int maxSize)
                {
                    this.keys = new StockInfo[maxSize+1];
                    keys[0] = new StockInfo();
                    for (int i = 1; i < this.keys.length; i++)
                    {
                        keys[i] = new StockInfo();
                    }
                    this.heapSize = 0;
                }


                public void buildHeap()
                {
                    for (int i = heapSize; i >= 1; i--)
                    {
                        sink(i);
                    }
                }

                private void swim(int i)
                {
                    while (this.keys[parent(i)].getAnswer().length() > this.keys[i].getAnswer().length())
                    {
                        exchange(parent(i), i);
                        i = parent(i);
                    }
                }

                private void sink(int i)
                {
                    int minItem = i;
                    if(left(i) > heapSize)
                    {
                        minItem = i;
                    }
                    else
                    {
                        if (this.keys[i].getAnswer().length() > this.keys[left(i)].getAnswer().length())
                        {
                            minItem = left(i);
                        }
                        else
                        {
                            minItem = i;
                        }
                    }
                    if(right(i) > heapSize)
                    {
                        minItem = minItem;
                    }
                    else if (this.keys[right(i)].getAnswer().length() < this.keys[minItem].getAnswer().length())
                    {
                        minItem = right(i);
                    }
                    if (minItem != i)
                    {
                        exchange(minItem, i);
                        sink(minItem);
                    }
                }

                public StockInfo extractMin()
                {
                    StockInfo si= this.keys[1];
                    exchange(1, heapSize);
                    heapSize--;
                    sink(1);
                    return si;
                }
            }


        }

        class StockInserctionSorter implements StockSorter
        {
            @Override
            public StockInfo[] sort(StockInfo[] info)
            {
                return sort(info, true);
            }

            @Override
            public StockInfo[] sort(StockInfo[] info, boolean order)
            {
                StockInfo[] a = info.clone();
                for (int i = 1; i < info.length; i++)
                {
                    StockInfo key = a[i];
                    int j = i - 1;
                    if (order)
                    {
                        while (j >= 0 && a[j].getAnswer().length() > key.getAnswer().length())
                        {
                            a[j + 1] = a[j];
                            j--;
                        }
                    }
                    else
                    {
                        while (j >= 0 && a[j].getAnswer().length() < key.getAnswer().length())
                        {
                            a[j + 1] = a[j];
                            j--;
                        }
                    }
                    a[j+1] = key;

                }
                return a;
            }
        }

        class StockSelectedSorter implements StockSorter
        {
            @Override
            public StockInfo[] sort(StockInfo[] info)
            {
                return sort(info ,true);
            }


            @Override
            public StockInfo[] sort(StockInfo[] info, boolean order)
            {
                StockInfo[] infos = info.clone();
                for (int i = info.length - 1; i >= 0; i--)
                {
                    if(order)
                    {
                        exchange(info, i, maximum(infos, i));
                    }
                    else
                    {
                        exchange(info, i, minimum(infos, i));
                    }
                }
                return infos;
            }

            private int maximum(StockInfo[] a, int endIndex)
            {
                int maxIndex = 0;
                for (int i = 0; i <= endIndex; i++)
                {
                    if (a[maxIndex].getAnswer().length() < a[i].getAnswer().length())
                    {
                        maxIndex = i;
                    }
                }
                return maxIndex;
            }

            private void exchange(StockInfo[] a, int i, int j)
            {
                StockInfo m = a[i];
                a[i] = a[j];
                a[j] = m;
            }

            private int minimum(StockInfo[] a, int endIndex)
            {
                int minIndex = 0;
                for (int i = 0; i < endIndex; i++)
                {
                    if (a[minIndex].getAnswer().length() > a[i].getAnswer().length())
                    {
                        minIndex = i;
                    }
                }
                return minIndex;
            }
        }

        stockSorter = new MergeSorter();
    }

    public static void main(String[] args) {
	// write your code here
        if(args.length < 2){
            System.exit(0);
        }
        String filePath = args[0];
        String targetPath = args[1];

        //数据读取
        StockInfo[] stocks = fileHandler.getStockInfoFromFile(filePath);
        if(stocks != null)
            System.out.println("数据读入成功");

        //数据排序
        StockInfo[] sortedStocks = stockSorter.sort(stocks);
        System.out.println("排序结束");

        int writeLenght = fileHandler.setStockInfo2File(targetPath,sortedStocks);
        Formatter formatter = new Formatter(System.out);
        if(writeLenght == sortedStocks.length)
            formatter.format("写入操作成功，共写入%d条数据",writeLenght);
        else
            formatter.format("写入失败");

    }

}
